---
title: 'watch'
section: 'API'
subSection: 'Utils'
description: 'watch for changes.'
---

# `watch`

## Subscription via a getter

This utility supports subscribing to multiple proxy objects (unlike `subscribe` which listens to only a single proxy). Proxy objects are subscribed with a `get` function passed to the callback.

Any changes to the proxy object (or its child proxies) will rerun the callback.

Also note the callback will run once immediately when `watch` is called, even if the proxies have not been yet mutated, to establish the initial subscriptions.

```js
import { proxy } from 'valtio'
import { watch } from 'valtio/utils'

const userState = proxy({ user: { name: 'Juuso' } })
const sessionState = proxy({ expired: false })

watch((get) => {
  // `get` adds `sessionState` to this callback's watched proxies
  get(sessionState)
  const expired = sessionState.expired
  // Or call it inline
  const name = get(userState).user.name
  console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
})
// 'Juuso's session is valid'
sessionState.expired = true
// 'Juuso's session is expired'
```

## Cleanup

You may return a cleanup function that runs both:

- Before each re-invocation of the callback (i.e. due to a watched proxy changing)
- When the `watch` itself is stopped (by calling the cleanup function returned by `watch`)

```js
watch((get) => {
  const expired = get(sessionState).expired
  const name = get(userState).user.name
  console.log(`${name}'s session is ${expired ? 'expired' : 'valid'}`)
  return () => {
    if (expired) {
      console.log('Cleaning up')
    }
  }
})
// Output from 1st immediate invocation of the callbcak
// 'Juuso's session is valid'

// Changing a dependency will invoke the cleanup callback first,
// but the captured `expired` is false, so we only see output from the
// 2nd invocation of the callback.
sessionState.expired = true
// 'Juuso's session is expired'

// Changing a dependency will again invoke the cleanup callback,
// and `expired` is true now, so we output from both our cleanup
// function as well as the 3rd invocation of the callback.
setTimeout(() => {
  userState.user.name = 'Anonymous'
}, 200)
// 200ms -> 'Anonymous's session is expired'
// 'Cleaning up' logged
```

## Gotchas

If you remove the setTimeout in the example above, `'Juuso's session is expired'` will become `'Anonymous's session is expired'` and it will be logged twice. Valtio will batch updates by default. You may pass `{sync: true}` as a second argument to `watch` to disable batching.

## No usage tracking

`watch` currently does not implement the usage tracking of `useSnapshot`, so the callback will rerun anytime a watched proxy (or child proxy) has any fields mutated, regardless of the fields accessed within the `callback`'s code.

And the return value of `get` is just the proxy itself, not a snapshot.

This is because `watch` is a vanilla primitive built on top of `subscribe`. It is potentially possible for `watch`, or a new `watch`-like method, to implement usage tracking in the future, see [this discussion](https://github.com/pmndrs/valtio/discussions/640) if interested.
